#pragma once
#include <iostream>
#include <memory>
#include <sys/select.h>
#include "Logger.hpp"
#include "Socket.hpp"

const static int gsize = sizeof(fd_set) * 8;
const static int gdefaultfd = -1;

class SelectServer
{
public:
    SelectServer(uint16_t port)
        : _listenfd(std::make_unique<TcpSocket>(port))
    {
        _listenfd->BuildSocket(port);
        for (int i = 0; i < gsize; i++)
        {
            fd_arry[i] = gdefaultfd;
        }
        fd_arry[0] = _listenfd->SockFd();
    }
    void Accepter()
    {
        InetAddr clientaddr;
        int sockfd = _listenfd->Accept(&clientaddr);
        if (sockfd > 0)
        {
            LOG(LogLevel::INFO) << "get new sockfd: " << sockfd << ", client addr: " << clientaddr.ToString();

            int pos = 0;
            for (; pos < gsize; pos++)
            {
                if (fd_arry[pos] == gdefaultfd)
                {
                    fd_arry[pos] = sockfd;
                    break;
                }
                if (pos == gsize)
                {
                    LOG(LogLevel::WARNING) << "文件描述符已满";
                    close(sockfd);
                }
            }
        }
    }
    void Recver(int index)
    {
        int sockfd = fd_arry[index];
        char buffer[1024];
        buffer[0] = 0;
        ssize_t n = recv(sockfd, buffer, sizeof(buffer), 0);
        if (n > 0)
        {
            buffer[n] = 0;
            std::cout << "client say# " << buffer << std::endl;
            std::string str = "server echo# ";
            str += buffer;
            send(sockfd, str.c_str(), str.size(), 0);
        }
        else if (n == 0)
        {
            LOG(LogLevel::INFO) << "client quit, me too: " << fd_arry[index];
            fd_arry[index] = defaultfd;
            close(sockfd);
        }
        else
        {
            LOG(LogLevel::WARNING) << "recv error: " << fd_arry[index];
            fd_arry[index] = defaultfd;
            close(sockfd);
        }
    }
    void EventDispatcher(fd_set &rfd)
    {
        LOG(LogLevel::INFO) << "fd就绪,有新事件到来";
        // 2.获取链接
        for (int i = 0; i < gsize; i++)
        {
            if (fd_arry[i] == gdefaultfd)
                continue;
            if (FD_ISSET(fd_arry[i], &rfd))
            {
                if (fd_arry[i] == _listenfd->SockFd())
                {
                    Accepter(); // 链接管理器
                }
                else
                {
                    Recver(i); // IO处理器
                }
            }
        }
        // 3.读写IO
    }
    void Run()
    {
        while (true)
        {
            // 1.调用select等待
            // 返回值等于0表示超时；返回值大于0表示有多少个fd就绪；返回值小于0表示select调用出错
            int maxfd = defaultfd;
            fd_set rfd;
            FD_ZERO(&rfd);
            struct timeval timeout = {0, 0}; // 表示非阻塞等待
            for (int i = 0; i < gsize; i++)
            {
                if (fd_arry[i] == gdefaultfd)
                    continue;
                FD_SET(fd_arry[i], &rfd);
                if (maxfd < fd_arry[i])
                {
                    maxfd = fd_arry[i];
                }
                LOG(LogLevel::DEBUG) << "添加fd:" << fd_arry[i];
            }
            int n = select(maxfd + 1, &rfd, nullptr, nullptr, nullptr);
            switch (n)
            {
            case 0:
                LOG(LogLevel::DEBUG) << "超时了... " << "剩余时间：" << timeout.tv_sec << " : " << timeout.tv_usec;
                break;
            case -1:
                LOG(LogLevel::ERROR) << "select调用出错";
            default:
                EventDispatcher(rfd);
                break;
            }
        }
    }
    ~SelectServer() {}

private:
    std::unique_ptr<Socket> _listenfd;
    int fd_arry[gsize];
};
